﻿using System;

namespace core
{
    /// <summary>Trieda INodeList_VirtualItems</summary>
    public class INodeList_VirtualItems : INodeList
    {
        /// <summary>Trieda INodeComparer</summary>
        protected class INodeComparer : System.Collections.Generic.IComparer<INode>
        {
            protected delegate int OnCompare(INode N1, INode N2);
            protected OnCompare FCompareMethod; // Metoda porovnania

            /// <summary>Porovnanie podla nazvu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Asc(INode N1, INode N2)
            {
                return string.Compare(((INodeData_VIRTUAL_ITEM)N1.NodeData).Name, ((INodeData_VIRTUAL_ITEM)N2.NodeData).Name);
            }
            /// <summary>Porovnanie podla nazvu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Desc(INode N1, INode N2)
            {
                return -string.Compare(((INodeData_VIRTUAL_ITEM)N1.NodeData).Name, ((INodeData_VIRTUAL_ITEM)N2.NodeData).Name);
            }
            /// <summary>Porovnanie podla pripony asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Asc(INode N1, INode N2)
            {
                int R = string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Asc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla pripony desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Desc(INode N1, INode N2)
            {
                int R = -string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Desc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla velkosti asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Asc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Asc(N1, N2);
                return N1.Size > N2.Size ? 1 : -1;
            }
            /// <summary>Porovnanie podla velkosti desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Desc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Desc(N1, N2);
                return N1.Size > N2.Size ? -1 : 1;
            }
            /// <summary>Porovnanie podla datumu modifikacie asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Asc(INode N1, INode N2)
            {
                int R = DateTime.Compare(((INodeData_VIRTUAL_ITEM)N1.NodeData).DModify, ((INodeData_VIRTUAL_ITEM)N2.NodeData).DModify);
                if (R == 0) return Compare_0_Asc(N1, N2);
                return R;
            }
            /// <summary>Porovnanie podla datumu modifikacie desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Desc(INode N1, INode N2)
            {
                int R = -DateTime.Compare(((INodeData_VIRTUAL_ITEM)N1.NodeData).DModify, ((INodeData_VIRTUAL_ITEM)N2.NodeData).DModify);
                if (R == 0) return Compare_0_Desc(N1, N2);
                return R;
            }
            /// <summary>Porovnanie podla plneho nazvu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_5_Asc(INode N1, INode N2)
            {
                return string.Compare(((INodeData_VIRTUAL_ITEM)N1.NodeData).OriginalPath, ((INodeData_VIRTUAL_ITEM)N2.NodeData).OriginalPath);
            }
            /// <summary>Porovnanie podla plneho nazvu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_5_Desc(INode N1, INode N2)
            {
                return -string.Compare(((INodeData_VIRTUAL_ITEM)N1.NodeData).OriginalPath, ((INodeData_VIRTUAL_ITEM)N2.NodeData).OriginalPath);
            }

            /// <summary>Konstruktor</summary>
            /// <param name="pCol">triediaci stlpec</param>
            /// <param name="pDirection">smer</param>
            public INodeComparer(int pCol, bool pDirection)
            {
                switch (pCol)
                {
                    case 5: if (pDirection) FCompareMethod = Compare_5_Asc; else FCompareMethod = Compare_5_Desc; break;
                    case 4: if (pDirection) FCompareMethod = Compare_4_Asc; else FCompareMethod = Compare_4_Desc; break;
                    case 2: if (pDirection) FCompareMethod = Compare_2_Asc; else FCompareMethod = Compare_2_Desc; break;
                    case 1: if (pDirection) FCompareMethod = Compare_1_Asc; else FCompareMethod = Compare_1_Desc; break;
                    default: if (pDirection) FCompareMethod = Compare_0_Asc; else FCompareMethod = Compare_0_Desc; break;
                }
            }

            /// <summary>Compare metoda</summary>
            /// <param name="x">objekt 1</param>
            /// <param name="y">objekt 2</param>
            /// <returns>vysledok porovnania</returns>
            int System.Collections.Generic.IComparer<INode>.Compare(INode x, INode y)
            {
                return FCompareMethod(x, y); // Volam porovnavaciu metodu
            }
        }

        protected string FParentPath; // Cesta pre navrat
        protected System.Collections.Generic.List<INode> FDirs;
        protected System.Collections.Generic.List<INode> FFiles;

        public string ListDescription; // Popis zoznamu

        /// <summary>Konstruktor</summary>
        public INodeList_VirtualItems(string pParentPath, bool pCreateBackItem = true)
        {
            // Inicializacia
            ID = NODE_LIST_ID_VIRTUAL;
            FColsCount = 6;
            FEnableVisibilityMask = 0x3e; FDefVisibilityMask = 0x3f;
            FParentPath = pParentPath;
            FHasBackItem = pCreateBackItem;
            ListDescription = "";
            if (FHasBackItem)
            {
                INode N = new INode(); N.ID = INode.NODE_ID_BACK_ITEM; AddNode(N);
            }
            FDirs = new System.Collections.Generic.List<INode>();
            FFiles = new System.Collections.Generic.List<INode>();
        }
        /// <summary>Vymazanie obsahu zoznamu</summary>
        public override void Clear()
        {
            base.Clear(); // Volam predchodcu
            if (FHasBackItem)
            {
                INode N = new INode(); N.ID = INode.NODE_ID_BACK_ITEM; AddNode(N);
            }
        }

        /// <summary>Ziskanie nazvu stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov alebo prazdny retazec</returns>
        public override string GetColumnName(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return lang.NODE_LIST_VIRTUAL_TEXT_1;
                case 1: return lang.NODE_LIST_VIRTUAL_TEXT_2;
                case 2: return lang.NODE_LIST_VIRTUAL_TEXT_3;
                case 3: return lang.NODE_LIST_VIRTUAL_TEXT_4;
                case 4: return lang.NODE_LIST_VIRTUAL_TEXT_5;
                case 5: return lang.NODE_LIST_VIRTUAL_TEXT_6;
                default: return "";
            }
        }
        /// <summary>Ziskanie zarovnania stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>zarovnanie</returns>
        public override System.Windows.Forms.HorizontalAlignment GetColumnAlignment(int pIndex)
        {
            switch (pIndex)
            {
                case 2:
                    return System.Windows.Forms.HorizontalAlignment.Right;
                case 3:
                case 4:
                    return System.Windows.Forms.HorizontalAlignment.Center;
                default: return System.Windows.Forms.HorizontalAlignment.Left;
            }
        }

        /// <summary>Test ci sa node moze expandovat</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeExpand(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (((INodeData_VIRTUAL_ITEM)N.NodeData).OriginalID)
            {
                case INode.NODE_ID_LOCAL_ITEM: 
                    return N.IsDirectory;
                default: return false;
            }
        }
        /// <summary>Ziskanie expandovacej cesty node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>cesta</returns>
        public override string GetNodeExpandPath(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return ""; // Ziskam platny node

            switch (((INodeData_VIRTUAL_ITEM)N.NodeData).OriginalID)
            {
                case INode.NODE_ID_LOCAL_ITEM:
                    return ((INodeData_VIRTUAL_ITEM)N.NodeData).OriginalPath;
                default: return "";
            }
        }
        /// <summary>Test ci je mozne skryt stlpec</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanHideColumn(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return false;
                default: return true;
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string CurrentPath
        {
            get
            {
                return "";
            }
        }
        /// <summary>Property: KeyValue</summary>
        public override string KeyValue
        {
            get
            {
                return IFileSystem.ExtractName(FParentPath).ToLower();
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string ParentPath
        {
            get
            {
                return FParentPath;
            }
        }
        /// <summary>Test ci sa node moze otvorit</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeOpen(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (((INodeData_VIRTUAL_ITEM)N.NodeData).OriginalID)
            {
                case INode.NODE_ID_LOCAL_ITEM: return N.IsFile;
                default: return false;
            }
        }
        /// <summary>Property: CanSort</summary>
        public override bool CanSort
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test ci je mozne podla zadaneho stlpca triedit</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool IsSortColumn(int pIndex)
        {
            switch (pIndex)
            {
                case 3:
                    return false;
                default: return true;
            }
        }
        /// <summary>Property: CanSelect</summary>
        public override bool CanSelect
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanSelectNode(INode pNode)
        {
            if (pNode == null) return false; // Ziskam platny node

            switch (pNode.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: IsCopySource</summary>
        public override bool IsCopySource
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: IsCopySourceItem</summary>
        public override bool IsCopySourceItem(int pIndex)
        {
            if (!IsCopySource) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }

        /// <summary>Vytvorenie textov pre zobrazenie</summary>
        /// <param name="pNode">objekt node</param>
        public override void CreateDisplayStrings(INode pNode)
        {
            if (pNode.DisplayStrings != null) return; // Uz su vytvorenie?

            pNode.DisplayStrings = new string[ColsCount]; // Alokujem retazec
            switch (pNode.ID) // Podla typu node
            {
                case INode.NODE_ID_BACK_ITEM:
                    {
                        pNode.DisplayStrings[0] = ICore.BoundString("[", "..", "]", IApp.Settings.FileExplorer_DirsInBraces);
                        pNode.DisplayStrings[2] = lang.NODE_LIST_VIRTUAL_TEXT_7;
                        pNode.DefaultImageIndex = -1;
                    } break;
                case INode.NODE_ID_VIRTUAL_ITEM:
                    {
                        if (pNode.IsDirectory)
                        {
                            pNode.DisplayStrings[0] = ICore.BoundString("[", pNode.Name, "]", IApp.Settings.FileExplorer_DirsInBraces);
                            if (pNode.ValidSize) pNode.DisplayStrings[2] = ICore.Size2String((ulong)pNode.Size, IApp.Settings.FileExplorer_DisplaySizeMode);
                            else pNode.DisplayStrings[2] = lang.NODE_LIST_VIRTUAL_TEXT_8;
                            pNode.DefaultImageIndex = 0; // Default ikona
                        }
                        else
                        {
                            pNode.DisplayStrings[0] = pNode.NameOnly; // Len nazov
                            if (pNode.DisplayStrings[0] == "") pNode.DisplayStrings[0] = pNode.Name; else pNode.DisplayStrings[1] = pNode.Ext; // Pripona
                            pNode.DisplayStrings[2] = ICore.Size2String((ulong)pNode.Size, IApp.Settings.FileExplorer_DisplaySizeMode); // Velkost
                            pNode.DefaultImageIndex = 1; // Default ikona
                        }
                        pNode.DisplayStrings[3] = pNode.AttributesAsString;
                        pNode.DisplayStrings[4] = ICore.DateTime2Str(pNode.DLastModify);
                        pNode.DisplayStrings[5] = ((INodeData_VIRTUAL_ITEM)pNode.NodeData).OriginalPath;
                    } break;
            }
        }
        /// <summary>Triedenie obsahu zoznamu</summary>
        /// <param name="pColumn">stlpec</param>
        /// <param name="pAsc">smer</param>
        public override void Sort(int pColumn, bool pAsc)
        {
            int S = IsBackNode(0) ? 1 : 0; // Urcim zaciatok
            if (DirsCount > 1)
            {
                FItems.Sort(S, DirsCount, new INodeComparer(0, pAsc));
            }
            if (FilesCount > 1)
            {
                FItems.Sort(S + DirsCount, FilesCount, new INodeComparer(pColumn, pAsc));
            }
        }
        /// <summary>Vytvorenie klonu zoznamu</summary>
        /// <returns>objekt zoznamu</returns>
        public override INodeList CloneList()
        {
            return new INodeList_VirtualItems(FParentPath, FHasBackItem);
        }

        /// <summary>Zaradenie node</summary>
        /// <param name="pNode">objekt node</param>
        /// <param name="pFullName">plny nazov</param>
        public void AddNewNode(INode pNode, string pFullName)
        {
            INode N = new INode(); N.NodeData = new INodeData_VIRTUAL_ITEM();
            N.ID = INode.NODE_ID_VIRTUAL_ITEM; // Vytvorim node

            INodeData_VIRTUAL_ITEM ND = (INodeData_VIRTUAL_ITEM)N.NodeData; // Vyplnim data
            ND.OriginalPath = pFullName;
            ND.OriginalID = pNode.ID;
            ND.Name = pNode.Name; ND.Size = pNode.Size; ND.Attributes = pNode.Attributes; ND.DModify = pNode.DLastModify;

            if (N.IsDirectory) FDirs.Add(N); else FFiles.Add(N);
        }
        /// <summary>Zaradenie node</summary>
        /// <param name="pOriginalID">originalne ID node</param>
        /// <param name="pName">nazov</param>
        /// <param name="pSize">dlzka</param>
        /// <param name="pAttr">atributy</param>
        /// <param name="pDModify">datum zmeny</param>
        /// <param name="pFullName">plny nazov</param>
        public void AddNewNode(int pOriginalID, string pName, long pSize, uint pAttr, DateTime pDModify, string pFullName)
        {
            INode N = new INode(); N.NodeData = new INodeData_VIRTUAL_ITEM();
            N.ID = INode.NODE_ID_VIRTUAL_ITEM; // Vytvorim node

            INodeData_VIRTUAL_ITEM ND = (INodeData_VIRTUAL_ITEM)N.NodeData; // Vyplnim data
            ND.OriginalPath = pFullName;
            ND.OriginalID = pOriginalID;
            ND.Name = pName; ND.Size = pSize; ND.Attributes = pAttr; ND.DModify = pDModify;

            if (N.IsDirectory) FDirs.Add(N); else FFiles.Add(N);
        }
        /// <summary>Vytvorenie jedneho zoznamu</summary>
        public void CompleteList()
        {
            foreach (INode N in FDirs) AddNode(N);
            foreach (INode N in FFiles) AddNode(N);
            FDirs.Clear(); FFiles.Clear();
        }
    }
}
